//  Copyright (c) 2024 Huawei Technologies Co., Ltd.
//  openUBMC is licensed under Mulan PSL v2.
//  You can use this software according to the terms and conditions of the Mulan PSL v2.
//  You may obtain a copy of Mulan PSL v2 at:
//        #  http://license.coscl.org.cn/MulanPSL2
//  THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
//  EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
//  MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
//  See the Mulan PSL v2 for more details.

export enum TpcmTabName {
  BOOT_METRICS = 'BOOT_METRICS',
  VM_BOOT_METRICS = 'VM_BOOT_METRICS',
  SECURE_BOOT = 'SECURE_BOOT',
  HARDWARE_ID = 'HARDWARE_ID'
}

export interface SecureBootEntry {
  signature: string;
  verificationResult: number;
  name: string;
  version: string;
}

export interface IdentityEntryDetails {
  actualDigest: string;
  actualIdentifier: string;
  name: string;
  standardDigest: string;
  standardIdentifier: string;
  status: number;
}

export interface IdentityEntry {
  comparedResult: number;
  details: IdentityEntryDetails[];
  name: string;
}

export interface VmComponent {
  measuredObject: string;
  version: string;
  actualDigest: string;
  standardDigest: string;
  vpcr: string;
  isMatch: boolean;
  parent: VmDataEntry | null;
}

export interface VmDataEntry {
  name: string;
  id: string;
  uuid: string;
  isMatch: boolean;
  measureEnabled: boolean;
  measureControlAllowed: boolean;
  hostingSystemId: number;
  components: VmComponent[];
}

export interface VmData {
  count: number;
  virtualMachines: VmDataEntry[];
}

export interface VmModifyParams {
  hostingSystemId: number;
  measureEnabled?: boolean;
  measureControlAllowed?: boolean;
  reauthKey: string;
}

export interface CurrDataEntry extends VmDataEntry {
  editData: {
    isEditing: boolean;
    measureEnabled: boolean;
    measureControlAllowed: boolean;
  };
}

export interface UpdateVmDigestParams {
  hostingSystemId: number;
  vmIds: string[];
  measuredObject: string;
  standardDigest: string;
  reauthKey?: string;
}

enum DetailStatus {
  NORMAL = 0,
  PLUGIN = 1,
  REMOVE = 2,
  UPDATE = 3
}

const detailStatusText = new Map<DetailStatus, string>([
  [DetailStatus.NORMAL, 'NORMAL'],
  [DetailStatus.PLUGIN, 'PLUGIN'],
  [DetailStatus.REMOVE, 'REMOVE'],
  [DetailStatus.UPDATE, 'UPDATE'],
]);

export const detailKeyList = [
  'name',
  'actualIdentifier',
  'standardIdentifier',
  'status',
  'actualDigest',
  'standardDigest',
] as const;
export const miniViewDetailKeyList = [
  'name',
  'status',
  'actualIdentifier',
  'standardIdentifier',
  'actualDigest',
  'standardDigest',
] as const;

const detailLabel = new Map<keyof IdentityEntryDetails, string>([
  ['name', 'TPCM_DEVICE_POSITION'],
  ['status', 'TPCM_DEVICE_STATUS'],
  ['actualIdentifier', 'TPCM_ACTUAL_IDENTIFIER'],
  ['standardIdentifier', 'TPCM_STANDARD_IDENTIFIER'],
  ['actualDigest', 'TPCM_ACTUAL_DIGEST'],
  ['standardDigest', 'TPCM_STANDARD_DIGEST'],
]);

export function getDetailLabel(key: keyof IdentityEntryDetails): string {
  return detailLabel.get(key) as string;
}

export function getStateStyleClass(status: number): string {
  return status === DetailStatus.NORMAL ? 'primary' : 'danger';
}

function getStatusText(status: number): string {
  switch (status) {
    case DetailStatus.NORMAL:
    case DetailStatus.PLUGIN:
    case DetailStatus.REMOVE:
    case DetailStatus.UPDATE:
      return detailStatusText.get(status) as string;
    default:
      return 'FAILED';
  }
}

export function getStatusLabel(status: number): string {
  return `TPCM_DEVICE_STATUS_${getStatusText(status)}`;
}

function pascalToCamel(key: string): string {
  return key.charAt(0).toLowerCase() + key.slice(1);
}

function parseData<
  T extends object,
  K extends readonly string[],
>(rawData: any, omits: readonly string[]): Omit<T, K[number]> {
  return Object.fromEntries(
    Object
      .keys(rawData)
      .filter((key) => !omits.includes(key))
      .map((key) => [pascalToCamel(key), rawData[key]]),
  ) as Omit<T, K[number]>;
}

export function parseVmRawData(vm: any): VmDataEntry {
  const commonData = parseData<VmDataEntry, ['uuid', 'components']>(vm, ['UUID', 'Components']);
  const vmEntry = {
    ...commonData,
    uuid: vm.UUID,
    components: vm.Components.map((component: any) => ({
      ...parseData<VmComponent, ['vpcr']>(component, ['vPCR']),
      vpcr: component.vPCR,
      parent: null,
    })) as VmComponent[],
  };
  vmEntry.components.forEach(component => component.parent = vmEntry);
  return vmEntry;
}